home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / browse.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  45KB  |  1,921 lines

  1. /*
  2.  * $Id: browse.c,v 0.91 1994/02/20 00:53:29 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *  Image browser. The thumbnail size can be 80x60 (default) or 100x80.
  26.  *  Define S100x80 to get 100x80.
  27.  *
  28.  */
  29. #if !defined(lint) && defined(F_ID)
  30. char *id_ibrw = "$Id: browse.c,v 0.91 1994/02/20 00:53:29 zhao Pre-Release $";
  31. #endif
  32.  
  33.  
  34. #include "bit.h"
  35. #include "dmalloc.h"
  36. #include "extern.h"
  37.  
  38. /**************** Limits and defines **************************/
  39.  
  40. #define MAXDIR       7        /* max. simultanou dirs       */
  41. #define MAXTNI       15        /* max. icons per screen      */
  42. #define TNIQ         2        /* thumbnail image quality 0-2 */
  43. #define MAXFLSHOWN  16        /* thumbnail label limit      */
  44.  
  45. #ifdef S100x80
  46. #define ICON_W       100.0    /* thumbnail image width  */
  47. #define ICON_H       80.0    /* thumbnail image height */
  48. #else
  49. #define ICON_W       80.0
  50. #define ICON_H       60.0
  51. #endif
  52.  
  53. #define THUMBDIR     ".btn/"    /* thumbnail directory    */
  54. #define THUMBSIG     "BTN"    /* signatures             */
  55.  
  56. /* due to re-entrant problems, need to block activaties while loading */
  57. #define IB_BLOCK     fl_deactivate_all_forms()
  58. #define IB_UNBLOCK   fl_activate_all_forms()
  59.  
  60. /*************** Structure and its associated functions ******/
  61.  
  62. typedef struct thumb_
  63.   {
  64.       struct thumb_ *next;    /* link                           */
  65.       char *name;        /* original image name.           */
  66.       char *info;        /* original image dimension info  */
  67.       char *ifmt;        /* short format info              */
  68.       IPTR im;            /* the thumbnail image            */
  69.       int selected;        /* true if marked                 */
  70.   }
  71. Thumb_t;
  72.  
  73. static Thumb_t *ithumb[MAXDIR], *itail[MAXDIR];
  74. static int itotal[MAXDIR];
  75. static IPTR dir_image, unknown;
  76.  
  77. /* check if a thumbnail is a directory if no associated icon, t->im==0 */
  78.  
  79. #define T_ISDIR(t) (t->info || (t->ifmt && strcmp(t->ifmt,"Dir")==0))
  80.  
  81.  
  82. /*******************************************************************
  83.  * Allocate a thumbnail image structure and initialize
  84.  ******************************************************************/
  85.  
  86. /* Asuuming null pointers have all bits zero, we can save some time */
  87.  
  88. #if 1
  89. #define ithumb_alloc()   calloc(1, sizeof(Thumb_t));
  90. #else
  91.  
  92. /* The function version of ithumb_alloc */
  93. static Thumb_t *
  94. ithumb_alloc(void)
  95. {
  96.     Thumb_t *t = malloc(sizeof(*t));
  97.  
  98.     if (t)
  99.       {
  100.       t->next = 0;
  101.       t->name = t->info = t->ifmt = 0;
  102.       t->im = 0;
  103.       t->selected = 0;
  104.       }
  105.     return t;
  106. }
  107. #endif /* Use alloc macros */
  108.  
  109.  
  110. /********************************************************************
  111.  * Free a thumbnail image
  112.  ********************************************************************/
  113.  
  114. /* free the raster and its associated info */
  115. static void
  116. free_thumbnail_raster(Thumb_t * t)
  117. {
  118.     free_image(t->im);
  119.     t->im = 0;
  120.  
  121.     if (t->info)
  122.       {
  123.       free(t->info);
  124.       t->info = 0;
  125.       }
  126. }
  127.  
  128. /* free all memeory associatd with a thumbnail  */
  129. static void
  130. ithumb_free(Thumb_t * t)
  131. {
  132.     free_thumbnail_raster(t);
  133.     if (t->name)
  134.     free(t->name);
  135.     t->name = 0;
  136.     if (t->ifmt)
  137.     free(t->ifmt);
  138.     t->ifmt = 0;
  139.     free(t);
  140. }
  141.  
  142. /*********************************************************************
  143.  * Remove a thumbnail image from the list
  144.  *********************************************************************/
  145.  
  146. static void
  147. ithumb_del(register Thumb_t * t, register int br)
  148. {
  149.     register Thumb_t *p = ithumb[br], *q;
  150.  
  151.     if (p == t)
  152.       {
  153.       ithumb[br] = p->next;
  154.       if (itail[br] == t)
  155.           itail[br] = 0;
  156.       }
  157.     else
  158.       {
  159.       for (q = p; q && q->next != t; q = q->next)
  160.           ;
  161.       if (!q)
  162.           return;
  163.  
  164.       q->next = q->next->next;
  165.  
  166.       if (t == itail[br])
  167.           itail[br] = q;
  168.       }
  169.  
  170.     ithumb_free(t);
  171.     --itotal[br];
  172. }
  173.  
  174. /*******************************************************************
  175.  * Free all icon images, and leave original filename etc intact
  176.  *******************************************************************/
  177.  
  178. static void
  179. free_ibrowser_thumbnail_image(int br)
  180. {
  181.     Thumb_t *p;
  182.  
  183.     for (p = ithumb[br]; p; p = p->next)
  184.     free_thumbnail_raster(p);
  185. }
  186.  
  187. /********************************************************************
  188.  * Free the whole list
  189.  *******************************************************************/
  190. static void
  191. free_ibrowser(int br)
  192. {
  193.     Thumb_t *p, *q;
  194.  
  195.     for (p = ithumb[br]; p; p = q)
  196.       {
  197.       q = p->next;
  198.       ithumb_free(p);
  199.       }
  200.     ithumb[br] = itail[br] = 0;
  201.     itotal[br] = 0;
  202. }
  203.  
  204. /*******************************************************************
  205.  * Free all memeory used by image browsers
  206.  *******************************************************************/
  207. void
  208. free_all_ibrowsers(void)
  209. {
  210.     int i;
  211.  
  212.     for (i = 0; i < MAXDIR; i++)
  213.     free_ibrowser(i);
  214.     free_image(dir_image);
  215.     dir_image = 0;
  216.     free_image(unknown);
  217.     unknown = 0;
  218. }
  219.  
  220.  
  221. /*********************************************************************
  222.  * Append one at end
  223.  *********************************************************************/
  224.  
  225. static void
  226. append_ibrowser(int br, Thumb_t * t)
  227. {
  228.     if (!ithumb[br])
  229.       {
  230.       ithumb[br] = itail[br] = t;
  231.       ++itotal[br];
  232.       return;
  233.       }
  234.     itail[br]->next = t;
  235.     itail[br] = t;
  236.     ++itotal[br];
  237. }
  238.  
  239.  
  240. /**********************************************************************
  241.  * Local variables
  242.  *********************************************************************/
  243.  
  244. static FL_FORM *ibrowser[MAXDIR];
  245. static FL_OBJECT *icons[MAXDIR][MAXTNI], *title[MAXDIR], *nfiles[MAXDIR];
  246. static FL_OBJECT *dnbox[MAXDIR], *sld[MAXDIR], *pager[MAXDIR];
  247. static char *lastdir[MAXDIR];
  248. static char *pat = "*";
  249. static int offset[MAXDIR];
  250. static int tni_quality = TNIQ;
  251. static int fitexact;        /* bad idea to to fit exact */
  252. static char complete_dir[PATH_MAX];
  253.  
  254.  
  255. /**************** Local function (forward) ************/
  256.  
  257. #ifdef S100x80
  258. static void create_browser_100x80(int);
  259. #else
  260. static void create_browser_80x60(int);
  261. #endif
  262. static void clean_thumbnail_dir(const char *, int);
  263. static void make_complete_dir(const char *, char *);
  264.  
  265.  
  266. /**********************************************************************
  267.  * get an available index. If no space left, free one
  268.  ***********************************************************************/
  269. static int
  270. alloc_browser(const char *dir, int *br)
  271. {
  272.     static int lastb;
  273.     int i = 0, cached = 0;
  274.  
  275.     do
  276.       {
  277.       cached = (lastdir[i] && strcmp(lastdir[i], dir) == 0);
  278.       }
  279.     while (!cached && ++i < MAXDIR);
  280.  
  281.     if (!cached)
  282.       {
  283.       StrReDup(lastdir[lastb], dir);
  284.       i = lastb;
  285.       lastb = (lastb + 1) % MAXDIR;
  286.       }
  287.     *br = (i >= MAXDIR) ? -1 : i;
  288.     return cached;
  289. }
  290.  
  291. /**********************************************************************
  292.  * Write a thumbnail image to disk
  293.  *********************************************************************/
  294. static void
  295. ithumb_dump(Thumb_t * t)
  296. {
  297.     char buf[1024];
  298.  
  299.     strcat(strcpy(buf, THUMBDIR), t->im->ifile);
  300.  
  301.     M_info("IThunmGen", "Writing %s", buf);
  302.  
  303.     if ((t->im->fp = fopen(buf, "w")))
  304.       {
  305.       fprintf(t->im->fp, "%s\n%s\n%s\n", THUMBSIG, t->name, t->info);
  306.  
  307.       /*
  308.        * The loading routine really does not care what format the icons
  309.        * are in and we can write in any format, except IRIS RGB which
  310.        * does its own things with the filename
  311.        */
  312.  
  313.       JPEG1_dump(t->im);
  314.       close_image(t->im);
  315.       }
  316. }
  317.  
  318.  
  319. /**********************************************************************
  320.  * Check if a given name already has a thumbnail image and load the
  321.  * image if it does.
  322.  *********************************************************************/
  323. static int
  324. ithumb_load(Thumb_t * t)
  325. {
  326.     IPTR im = 0;
  327.     char buf[1024], info[128], name[128];
  328.     FILE *fp;
  329.     int isthumi;
  330.  
  331.     /* complete filename */
  332.     strcat(strcpy(buf, THUMBDIR), t->name);
  333.  
  334.     isthumi = (fp = fopen(buf, "r")) &&
  335.     fgets(buf, 1024, fp) &&
  336.     strncmp(buf, THUMBSIG, 3) == 0;
  337.  
  338.     if (isthumi)
  339.       {
  340.       register char *p = name;
  341.       Readline(p, fp);
  342.       p = info;
  343.       Readline(p, fp);
  344.       im = load_image_fp(fp, t->name);
  345.       close_image(im);
  346.       }
  347.  
  348.     if (im && im->ok)
  349.       {
  350.       free_thumbnail_raster(t);
  351.       t->info = strdup(info);
  352.       t->im = im;
  353.       }
  354.  
  355.     M_info("ThumbILoad", "%s Loading %s", t->im ? "OK" : "Bad", t->name);
  356.     errno = 0;
  357.  
  358.     return t->im ? 0 : -1;
  359. }
  360.  
  361. /********************************************************************
  362.  * Get thumbnail image size
  363.  ********************************************************************/
  364. static void
  365. get_tni_size(IPTR im, int *w, int *h)
  366. {
  367.     if (fitexact)
  368.       {
  369.       *w = ICON_W;
  370.       *h = ICON_H;
  371.       }
  372.     else
  373.       {
  374.       double xs = ICON_W / im->w;
  375.       double ys = ICON_H / im->h;
  376.  
  377.       xs = Min(xs, ys);
  378.       *w = xs * im->w;
  379.       *h = xs * im->h;
  380.       }
  381. }
  382.  
  383.  
  384. /**********************************************************************
  385.  * Given a filename, generate a thumbnail image out of it
  386.  **********************************************************************/
  387. static int
  388. ithumb_gen(Thumb_t * t)
  389. {
  390.     IPTR itmp;
  391.     int w, h;
  392.  
  393.     if ((itmp = load_image(t->name)))
  394.       {
  395.       /* might delete the wrong thing */
  396.       del_text();
  397.       del_marking();
  398.       free_thumbnail_raster(t);
  399.       t->info = strdup(image_vital_info(itmp));
  400.       get_tni_size(itmp, &w, &h);
  401.       img_scale(itmp, h, w, tni_quality, fitexact, 0);
  402.       t->im = itmp;
  403.       }
  404.     return t->im ? 0 : -1;
  405. }
  406.  
  407. /*************************************************************************
  408.  * Given a filename, either load, if exists already, or generate
  409.  * a thumbnail image if not or if the thumbnail is older than the
  410.  * image file
  411.  *************************************************************************/
  412. static void
  413. ithumb_update(Thumb_t * t, int update)
  414. {
  415.     char tfbuf[PATH_MAX];
  416.  
  417.     if (!update)
  418.       {
  419.       ithumb_load(t);
  420.       return;
  421.       }
  422.  
  423.     strcat(strcpy(tfbuf, THUMBDIR), t->name);
  424.  
  425.     /* generate a new thumbnail if it is older than image or there is none */
  426.     if ((f_mtime(t->name) > f_mtime(tfbuf)) || (!t->info && ithumb_load(t) < 0))
  427.       {
  428.       if (ithumb_gen(t) >= 0)
  429.           ithumb_dump(t);
  430.       }
  431. }
  432.  
  433. #include <sys/types.h>
  434. #include <sys/stat.h>
  435.  
  436. static int
  437. make_ithumb_dir(const char *dir)
  438. {
  439.     /*
  440.      * If dir already exists and permission is OK, don't have to try making
  441.      * thumbnail dir
  442.      */
  443.  
  444.     if (access(THUMBDIR, F_OK | X_OK) && mkdir(THUMBDIR, 0777))
  445.       {
  446.       Bark("MakeIconDir", "can't create %s%s", dir, THUMBDIR);
  447.       return -1;
  448.       }
  449.     errno = 0;
  450.     return 0;
  451. }
  452.  
  453. /********************************************************
  454.  * Remove thumbnails whose orignal images no longer exist
  455.  ********************************************************/
  456.  
  457. static void
  458. clean_thumbnail_dir(const char *dir, int br)
  459. {
  460.     char tdir[PATH_MAX + 1];
  461.     Dirlist *dl, *dls;
  462.     Thumb_t *t;
  463.     int n;
  464.  
  465.     strcat(strcpy(tdir, dir), THUMBDIR);
  466.     if (!is_valid_dir(tdir))
  467.     return;
  468.  
  469.     show_busy("DelIcons ...");
  470.     push_dir();
  471.  
  472.     /* Read dir list */
  473.     chdir(tdir);
  474.     dl = get_dir_list(tdir, 0, &n, 1);
  475.  
  476.     if (dl && n > 0)
  477.       {
  478.       for (dls = dl + n; dl < dls; dl++)
  479.         {
  480.         /* check for matches among original filenames */
  481.         for (t = ithumb[br]; t && strcmp(t->name, dl->name);
  482.              t = t->next)
  483.             ;
  484.         if (!t)
  485.           {
  486.               M_info("DelIcon", "Removing %s", dl->name);
  487.               remove(dl->name);
  488.           }
  489.  
  490.         }
  491.       }
  492.     pop_dir();
  493.     errno = 0;
  494.     end_busy();
  495. }
  496.  
  497. /*** When deleting orignal files, this routine will called */
  498. void
  499. del_thumbnail(const char *dir, const char *file)
  500. {
  501.     char cdir[PATH_MAX + 128];
  502.     char cfile[128];
  503.  
  504.     if (file && *file)
  505.       {
  506.       if (file[0] == '/')
  507.         {
  508.         split_fname(cdir, cfile, file);
  509.         fix_dir_tail(cdir);
  510.         strcat(strcat(cdir, THUMBDIR), cfile);
  511.         }
  512.       else
  513.         {
  514.         make_complete_dir(dir, cdir);
  515.         strcat(strcat(cdir, THUMBDIR), file);
  516.         }
  517.  
  518.       M_info("DelThumbI", "removing %s", cdir);
  519.  
  520.       if (access(cdir, F_OK) == 0 && remove(cdir))
  521.           M_warn("DelThumbI", cdir);
  522.       }
  523. }
  524.  
  525.  
  526. /******************************************************************
  527.  * Default images. Must be called from within fill_ibroser to
  528.  * suppress info reporting
  529.  ******************************************************************/
  530.  
  531. static void
  532. load_default_thumbi(void)
  533. {
  534.     if (!dir_image)
  535.     dir_image = load_image(get_HELPFile("dir80x60.icon"));
  536.     if (!unknown)
  537.     unknown = load_image(get_HELPFile("unknown.icon"));
  538. }
  539.  
  540. static Thumb_t *
  541. current_offset(int br)
  542. {
  543.     register int off = offset[br], i = 0;
  544.     register Thumb_t *t = ithumb[br];
  545.  
  546.     while (i < off)
  547.       {
  548.       t = t->next;
  549.       ++i;
  550.       }
  551.     return t;
  552. }
  553.  
  554. static const char *
  555. icon_label(Thumb_t * t)
  556. {
  557.     static char buf[PATH_MAX];
  558.     strcpy(buf, t->name);
  559.  
  560.     /*
  561.      * limit filename to MAXFLSHOWN chars so that it does not wander into
  562.      * next/previous icon space
  563.      */
  564.     if (strlen(buf) > MAXFLSHOWN)
  565.     buf[MAXFLSHOWN] = '\0';
  566.  
  567.     return strcat(strcat(buf, "\n"), t->info ? t->info : t->ifmt);
  568. }
  569.  
  570. /*********************************************************************
  571.  * Assign icon bitmap and labels from thumbnail images
  572.  *********************************************************************/
  573.  
  574. static void
  575. assign_icon(FL_OBJECT * ob, Thumb_t * t)
  576. {
  577.     IPTR im;
  578.  
  579.     if ((im = t->im))
  580.       {
  581.       fl_set_icon_bitmap(ob, im->w, im->h, im->mraster, 1);
  582.       }
  583.     else
  584.       {
  585.       /*
  586.        * dir entry either has t->info filled or ifmt == "Dir". t->info is
  587.        * freed after delall, so need check both
  588.        */
  589.       if (T_ISDIR(t))
  590.         {
  591.         if (dir_image)
  592.             fl_set_icon_bitmap(ob, dir_image->w,
  593.                        dir_image->h, dir_image->mraster, 1);
  594.         }
  595.       else
  596.         {
  597.         if (unknown)
  598.             fl_set_icon_bitmap(ob, unknown->w,
  599.                        unknown->h, unknown->mraster, 1);
  600.         }
  601.  
  602.       }
  603.  
  604.     /* Record filename for call back */
  605.     fl_set_icon_info(ob, t->name);
  606.     fl_set_object_label(ob, icon_label(t));
  607.     fl_set_icon(ob, t->selected);
  608. }
  609.  
  610. static void
  611. show_current_number(int br)
  612. {
  613.     int lastn;
  614.     char buf[128];
  615.  
  616.     /* last thumbnail sequence number */
  617.     lastn = (offset[br] + MAXTNI) > itotal[br] ?
  618.     itotal[br] : (offset[br] + MAXTNI);
  619.     sprintf(buf, "%d of %d", lastn, itotal[br]);
  620.     fl_set_object_label(nfiles[br], buf);
  621. }
  622.  
  623. /******************************************************************
  624.  * Assign icons and associated files. If update is positive, we
  625.  * generate thumbnails if it is not already there. If update
  626.  * is negative, do nothing. This implements paging without updating
  627.  * icons
  628.  ******************************************************************/
  629.  
  630. static int
  631. fill_ibrowser(int br, int update)
  632. {
  633.     Thumb_t *t = ithumb[br];
  634.     int i, off = offset[br], k = 0, total = itotal[br];
  635.     FL_OBJECT **ic = icons[br];
  636.     int savereport = report_level;
  637.  
  638.     report_level = -1;
  639.     show_busy("");
  640.  
  641.     load_default_thumbi();
  642.  
  643.     /* skip till we get to the offset */
  644.     while (k < off)
  645.       {
  646.       t = t->next;
  647.       k++;
  648.       }
  649.  
  650.  
  651.     /* block until we are done */
  652.     IB_BLOCK;
  653.  
  654.     /* if update, it looks better if we update as we go */
  655.  
  656.     if (update <= 0)
  657.       {
  658.       fl_freeze_form(ibrowser[br]);
  659.       fl_redraw_object(dnbox[br]);
  660.       }
  661.  
  662.     /* print current and total icons */
  663.     show_current_number(br);
  664.  
  665.     for (i = 0; (i + off) < total && i < MAXTNI && t; i++, t = t->next)
  666.       {
  667.       show_busy("");
  668.  
  669.       /* directory always has info filled */
  670.       if ((!t->info && update >= 0) || update > 0)
  671.           ithumb_update(t, update);
  672.  
  673.       /* if not updating, the whole box is cleared */
  674.       if (update > 0)
  675.           fl_hide_object_only(ic[i]);
  676.  
  677.       assign_icon(ic[i], t);
  678.       fl_show_object(ic[i]);
  679.       }
  680.  
  681.     for (; i < MAXTNI; i++)
  682.     fl_hide_object_only(ic[i]);
  683.  
  684.     IB_UNBLOCK;
  685.  
  686.     if (update <= 0)
  687.     fl_unfreeze_form(ibrowser[br]);
  688.  
  689.     report_level = savereport;
  690.     end_busy();
  691.     return 0;
  692. }
  693.  
  694.  
  695. /***********************************************************************
  696.  * List all dir entries and load thumbnail images
  697.  ***********************************************************************/
  698.  
  699. static int
  700. load_dir(const char *dname, int rescan)
  701. {
  702.     int n, br, cached, i;
  703.     Thumb_t *t;
  704.     Dirlist *dl, *dlh;
  705.     const char *ifmt;
  706.     long rlines;
  707.  
  708.     /* check if this dir is cached */
  709.  
  710.     show_busy("Reading Dir ...");
  711.  
  712.     if (!(dl = dlh = get_dir_list(dname, pat, &n, rescan)))
  713.       {
  714.       end_busy();
  715.       return -1;
  716.       }
  717.  
  718.     cached = alloc_browser(dname, &br);
  719.     end_busy();
  720.  
  721.     if ((cached && !rescan) || br < 0)
  722.     return br;
  723.  
  724.  
  725. #ifdef S100x80
  726.     create_browser_100x80(br);
  727. #else
  728.     create_browser_80x60(br);
  729. #endif
  730.  
  731.     rlines = progress_report("Checking Files ...", n);
  732.  
  733.     push_dir();
  734.  
  735.     chdir(dname);
  736.  
  737.     if (rescan)
  738.       {
  739.       /* signify all bitmaps are freed */
  740.       for (i = 0; i < 15; i++)
  741.           fl_set_icon_bitmap(icons[br][i], ICON_W, ICON_H, 0, 1);
  742.       /* now free it */
  743.       free_ibrowser(br);
  744.       }
  745.  
  746.     /* generate thumbnail image dir */
  747.     make_ithumb_dir(dname);
  748.  
  749.     /* Generate thumbnail images and load it. */
  750.     for (i = 0, dlh = dl + n; dl < dlh; dl++, i++)
  751.       {
  752.       REPORT(i, rlines);
  753.  
  754.       /* how to handle directories */
  755.       if (dl->type == FT_DIR)
  756.         {
  757.         if (dl->name[0] != '.')
  758.           {
  759.               t = ithumb_alloc();
  760.               t->info = strdup("Directory");
  761.               t->name = strdup(dl->name);
  762.               t->ifmt = strdup("Dir");
  763.               append_ibrowser(br, t);
  764.           }
  765.         }
  766.       else
  767.         {
  768.         if ((ifmt = is_image_file(dl->name)))
  769.           {
  770.               t = ithumb_alloc();
  771.               t->name = strdup(dl->name);
  772.               t->ifmt = strdup(ifmt);
  773.               append_ibrowser(br, t);    /* a place holder */
  774.           }
  775.         }
  776.       }
  777.  
  778.     remove_progress_report();
  779.  
  780.     fl_set_object_label(title[br], contract_dirname(dname, 28));
  781.     (itotal[br] < MAXTNI ? fl_hide_object_only : fl_show_object) (pager[br]);
  782.  
  783.     /* default is not to generate thumbnail images if not exist */
  784.     fill_ibrowser(br, rescan);
  785.  
  786.     pop_dir();
  787.  
  788.     return br;
  789. }
  790.  
  791. /*** Given a dirname, expand and append / */
  792. static void
  793. make_complete_dir(const char *dirname, char *okdir)
  794. {
  795.     int i;
  796.     /* generate a complete dirname */
  797.     if (dirname && *dirname)
  798.     strcpy(okdir, dirname);
  799.     else
  800.     getcwd(okdir, PATH_MAX - 2);
  801.  
  802.     fix_dirname(okdir);
  803.     i = strlen(okdir);
  804.  
  805.     /* append / to it */
  806.     if (okdir[i - 1] != '/')
  807.       {
  808.       okdir[i] = '/';
  809.       okdir[i + 1] = '\0';
  810.       }
  811. }
  812.  
  813.  
  814. /**********************************************************************
  815.  * Global entry point
  816.  **********************************************************************/
  817.  
  818. int
  819. ibrowse_dir(const char *dirname)
  820. {
  821.     int br;
  822.  
  823.     fl_deactivate_all_forms();
  824.  
  825.     make_complete_dir(dirname, complete_dir);
  826.  
  827.     push_dir();            /* save current dir */
  828.  
  829.     chdir(complete_dir);
  830.  
  831.     if ((br = load_dir(complete_dir, 0)) < 0)
  832.       {
  833.       Bark("IbrowseDir", complete_dir);
  834.       fl_activate_all_forms();
  835.       return -1;
  836.       }
  837.  
  838.  
  839.     bit_show_form(ibrowser[br], FL_PLACE_SIZE, 0, complete_dir);
  840.  
  841.     if (auto_remove_thumbnail)
  842.     clean_thumbnail_dir(complete_dir, br);
  843.  
  844.     pop_dir();
  845.  
  846.     fl_activate_all_forms();
  847.  
  848.     return 0;
  849. }
  850.  
  851. /* ARGSUSED */
  852. static void
  853. finish_it(FL_OBJECT * ob, long q)
  854. {
  855.     bit_hide_form(ibrowser[q]);
  856. }
  857.  
  858. /*****************************************************************
  859.  * Generate and write a thumbnail given an image. Return 1 if new
  860.  *****************************************************************/
  861.  
  862. /* ARGSUSED */
  863. static Thumb_t *
  864. img_update_icon(FL_OBJECT * ob, IPTR im, long br)
  865. {
  866.     Thumb_t *t;
  867.     const char *f = im->ifile;
  868.     int oldreport = report_level;
  869.     IPTR itm;
  870.     int w, h;
  871.  
  872.     for (t = ithumb[br]; t && strcmp(t->name, f); t = t->next)
  873.     ;
  874.  
  875.     if (t && (!t->info || !t->im))
  876.       {
  877.       report_level = -1;
  878.       itm = img_dup(im);
  879.  
  880.       /* this will prevent fill_ibrowser from reading disk file */
  881.       t->info = strdup(image_vital_info(itm));
  882.       get_tni_size(itm, &w, &h);
  883.  
  884.       show_busy("Scaling ...");
  885.       img_scale(itm, h, w, tni_quality, fitexact, 0);
  886.       t->im = itm;
  887.       ithumb_dump(t);
  888.       report_level = oldreport;
  889.       t->selected = 0;
  890.       end_busy();
  891.  
  892.       return (t->im && t->im->mraster) ? t : 0;
  893.       }
  894.     return 0;
  895. }
  896.  
  897. /*******************************************************************
  898.  * Handle mouse click on the thumbnail image. Load and display.
  899.  * of course if its thumbnail has not been made, make it
  900.  ********************************************************************/
  901.  
  902. static void
  903. handle_it(FL_OBJECT * ob, long q)
  904. {
  905.     IPTR im;
  906.     const char *fname = fl_get_icon_info(ob);
  907.     Thumb_t *t;
  908.  
  909.     if (!fl_get_icon_dblclk(ob))
  910.       {
  911.       register int i;
  912.       register FL_OBJECT **ic = icons[q];
  913.  
  914.       t = current_offset(q);
  915.       for (i = 0; i < MAXTNI && ob != ic[i]; i++)
  916.           t = t->next;
  917.       if (t)
  918.           t->selected = fl_get_icon(ob);
  919.       return;
  920.       }
  921.  
  922.     /* handle double click */
  923.     push_dir();
  924.     chdir(lastdir[q]);
  925.  
  926.     if (is_valid_dir(fname))
  927.       {
  928.       ibrowse_dir(fname);
  929.       pop_dir();
  930.       return;
  931.       }
  932.  
  933.     /*
  934.      * must prevent page fliping or any other activities as loading JPEG (and
  935.      * others ) is not re-entrant
  936.      */
  937.  
  938.     fl_deactivate_all_forms();
  939.  
  940.     del_text();
  941.     del_marking();
  942.  
  943.     if ((im = load_image(fname)))
  944.       {
  945.       free_image(imgptr);
  946.       imgptr = im;
  947.       imgptr->io->display(im, 0, always_clear);
  948.  
  949.       if (imgptr->more)
  950.           handle_multi_images(imgptr);
  951.  
  952.       /* returns icon if new */
  953.       if ((t = img_update_icon(ob, imgptr, q)))
  954.         {
  955.         fl_hide_object_only(ob);
  956.         assign_icon(ob, t);
  957.         fl_show_object(ob);
  958.         }
  959.       }
  960.  
  961.     fl_activate_all_forms();
  962.     pop_dir();
  963. }
  964.  
  965. /**********************************************************************
  966.  * New directory
  967.  **********************************************************************/
  968.  
  969. /* ARGSUSED */
  970. static void
  971. newdir_cb(FL_OBJECT * ob, long br)
  972. {
  973.     const char *ndir;
  974.     static char dbuf[PATH_MAX];
  975.     char prom[1024];
  976.  
  977.     getcwd(dbuf, PATH_MAX - 2);
  978.     sprintf(prom, "NewDir (current %s)", dbuf);
  979.  
  980.     if ((ndir = getstring(prom, "", 1)) && *ndir)
  981.       {
  982.  
  983.       strcpy(dbuf, ndir);
  984.       fix_dirname(dbuf);
  985.       if (is_valid_dir(dbuf))
  986.         {
  987.         ibrowse_dir(dbuf);
  988.         }
  989.       else
  990.         {
  991.         Bark("NewDir", "Bad dir %s", dbuf);
  992.         }
  993.       }
  994. }
  995.  
  996. /***********************************************************************
  997.  * Walk Up one level
  998.  **********************************************************************/
  999. /* ARGSUSED */
  1000. static void
  1001. parent_cb(FL_OBJECT * ob, long br)
  1002. {
  1003.     char dbuf[PATH_MAX], *p;
  1004.  
  1005.     strcpy(dbuf, lastdir[br]);
  1006.     /* lastdir always has the trailing /.  zap the tail */
  1007.     p = strrchr(dbuf, '/');
  1008.     *p = '\0';
  1009.     p = strrchr(dbuf, '/');
  1010.     *p = '\0';
  1011.     ibrowse_dir(dbuf);
  1012. }
  1013.  
  1014.  
  1015. /*************************************************************************
  1016.  * update all visible icons
  1017.  **************************************************************************/
  1018. /* ARGSUSED */
  1019. static void
  1020. update_cb(FL_OBJECT * ob, long br)
  1021. {
  1022.     fill_ibrowser(br, 1);
  1023. }
  1024.  
  1025. /*************************************************************************
  1026.  * Rescan directory and update all visible icons
  1027.  *************************************************************************/
  1028.  /* ARGSUSED */
  1029. static void
  1030. rescan_cb(FL_OBJECT * ob, long br)
  1031. {
  1032.     char dbuf[PATH_MAX];
  1033.  
  1034.     IB_BLOCK;
  1035.  
  1036.     /* can't use lastdir[br] directly as load_dir will do a free lastdir[br] */
  1037.     strcpy(dbuf, lastdir[br]);
  1038.     load_dir(dbuf, 1);
  1039.  
  1040.     /* also clean up the thumnail directory */
  1041.     clean_thumbnail_dir(dbuf, br);
  1042.  
  1043.     IB_UNBLOCK;
  1044. }
  1045.  
  1046. /*********************************************************************
  1047.  * Save the current state of marking information
  1048.  *********************************************************************/
  1049. static void
  1050. save_mark_info(int br)
  1051. {
  1052.     int i = 0, off = offset[br];
  1053.     Thumb_t *t = ithumb[br];
  1054.     FL_OBJECT **ic = icons[br];
  1055.  
  1056.     /* remember the marking info */
  1057.     while (i < off)
  1058.       {
  1059.       t = t->next;
  1060.       i++;
  1061.       }
  1062.  
  1063.     for (i = 0; i < MAXTNI && (i + off) < itotal[br] && t; i++, t = t->next)
  1064.     t->selected = fl_get_icon(ic[i]);
  1065. }
  1066.  
  1067. /***********************************************************************
  1068.  * Paging: This turns out a little tricker than previously thought because
  1069.  * no of the loading modules are re-entrant. Can't really allow next_cb
  1070.  * and prev_cb to run simultanously (that is, allow it to run only if
  1071.  * fill_ibrowser has finished.
  1072.  **********************************************************************/
  1073.  
  1074. static FL_OBJECT *upb[MAXDIR], *dnb[MAXDIR];
  1075.  
  1076. /***********************************************************************
  1077.  * Paging: up
  1078.  **********************************************************************/
  1079. /* ARGSUSED*/
  1080. static void
  1081. prev_cb(FL_OBJECT * ob, long br)
  1082. {
  1083.     save_mark_info(br);
  1084.  
  1085.     IB_BLOCK;
  1086.  
  1087.     if (offset[br] > 0)
  1088.       {
  1089.       if ((offset[br] -= MAXTNI) < 0)
  1090.           offset[br] = 0;
  1091.       fl_set_slider_value(sld[br], 1.0 - (float) offset[br] / itotal[br]);
  1092.       fill_ibrowser(br, control_down ? -1 : 0);
  1093.       }
  1094.  
  1095.     IB_UNBLOCK;
  1096. }
  1097.  
  1098. /**********************************************************************
  1099.  * Paging down
  1100.  **********************************************************************/
  1101.  
  1102. /* ARGSUSED */
  1103. static void
  1104. next_cb(FL_OBJECT * ob, long br)
  1105. {
  1106.     int lastn;
  1107.  
  1108.     save_mark_info(br);
  1109.  
  1110.     IB_BLOCK;
  1111.  
  1112.     if ((offset[br] + MAXTNI) < itotal[br])
  1113.       {
  1114.       offset[br] += MAXTNI;
  1115.  
  1116.       fill_ibrowser(br, control_down ? -1 : 0);
  1117.  
  1118.       lastn = (offset[br] + MAXTNI);
  1119.       lastn = (lastn > itotal[br] ? itotal[br] : lastn);
  1120.       fl_set_slider_value(sld[br], 1.0 - (float) lastn / itotal[br]);
  1121.       }
  1122.  
  1123.     IB_UNBLOCK;
  1124. }
  1125.  
  1126. /********************************************************************
  1127.  * This routine is called when the slider is RELEASED. This way, we
  1128.  * can advance or backup quickly without loading all the iocns in
  1129.  * between
  1130.  *******************************************************************/
  1131. static void
  1132. slider_cb(FL_OBJECT * ob, long br)
  1133. {
  1134.     double p = fl_get_slider_value(ob);
  1135.     int leftover = (itotal[br] % MAXTNI);
  1136.     int start;
  1137.  
  1138.     IB_BLOCK;
  1139.  
  1140.     if ((start = (1.0 - p) * (itotal[br] - leftover)) < 0)
  1141.     start = 0;
  1142.     offset[br] = start;
  1143.     fill_ibrowser(br, 0);
  1144.  
  1145.     IB_UNBLOCK;
  1146. }
  1147.  
  1148. /*************************************************************************
  1149. * Add all marked files to the file list
  1150. **************************************************************************/
  1151. /* ARGSUSED */
  1152. static void
  1153. add_cb(FL_OBJECT * ob, long br)
  1154. {
  1155.     Thumb_t *p = ithumb[br];
  1156.  
  1157.     push_dir();
  1158.     chdir(lastdir[br]);
  1159.  
  1160.     /* add all files that are selected, excluding directoies */
  1161.     while (p)
  1162.       {
  1163.       if (p->selected && !is_valid_dir(p->name))
  1164.           add_to_list(lastdir[br], p->name);
  1165.       p = p->next;
  1166.       }
  1167.     pop_dir();
  1168. }
  1169.  
  1170. /************************************************************************
  1171.  * Delete all marked icons
  1172.  ***********************************************************************/
  1173. /* ARGSUSED */
  1174. static void
  1175. del_cb(FL_OBJECT * ob, long br)
  1176. {
  1177.     Thumb_t *p = ithumb[br], *q;
  1178.  
  1179.     push_dir();
  1180.  
  1181.     chdir(lastdir[br]);
  1182.  
  1183.     /* if this cd fails, must not proceed, might delete the original image */
  1184.  
  1185.     if (chdir(THUMBDIR))
  1186.       {
  1187.       M_err("ChDir", "%s%s", lastdir[br], THUMBDIR);
  1188.       return;
  1189.       }
  1190.  
  1191.     while (p)
  1192.       {
  1193.       q = p->next;
  1194.       if (p->selected && !is_valid_dir(p->name))
  1195.         {
  1196.         remove(p->name);
  1197.         ithumb_del(p, br);
  1198.         M_info("DeleteIcon", p->name);
  1199.         }
  1200.       p = q;
  1201.       }
  1202.     pop_dir();
  1203.  
  1204.     /* re-fill */
  1205.     fill_ibrowser(br, 0);
  1206. }
  1207.  
  1208.  
  1209.  
  1210.  
  1211. /*******************************************************
  1212.  * Select all files
  1213.  ******************************************************/
  1214. /* ARGSUSED */
  1215. static void
  1216. mark_all(FL_OBJECT * ob, long br)
  1217. {
  1218.     Thumb_t *t = ithumb[br];
  1219.  
  1220.     while (t)
  1221.       {
  1222.       t->selected = 1;
  1223.       t = t->next;
  1224.       }
  1225.     fill_ibrowser(br, 0);
  1226. }
  1227.  
  1228. /*******************************************************
  1229.  * Unselected all files
  1230.  *******************************************************/
  1231. /* ARGSUSED*/
  1232. static void
  1233. unmark_all(FL_OBJECT * ob, long br)
  1234. {
  1235.     Thumb_t *t = ithumb[br];
  1236.  
  1237.     while (t)
  1238.       {
  1239.       t->selected = 0;
  1240.       t = t->next;
  1241.       }
  1242.     fill_ibrowser(br, 0);
  1243. }
  1244.  
  1245. /*********************************************************************
  1246.  * Delete all icons, but do not update the browser
  1247.  *********************************************************************/
  1248. /* ARGSUSED */
  1249. static void
  1250. delall_cb(FL_OBJECT * ob, long br)
  1251. {
  1252.     char dbuf[PATH_MAX];
  1253.  
  1254.     if (lastdir[br] && ithumb[br])
  1255.       {
  1256.       strcat(strcpy(dbuf, lastdir[br]), THUMBDIR);
  1257.       rm_all_files(dbuf, "*");
  1258.  
  1259.       /* warn only failed to remove */
  1260.       if (access(dbuf, F_OK) == 0 && rmdir(dbuf))
  1261.           M_warn("DelAll", "%s not removed", dbuf);
  1262.  
  1263.       free_ibrowser_thumbnail_image(br);
  1264.       fill_ibrowser(br, 0);
  1265.       }
  1266. }
  1267.  
  1268. /********************************************************************
  1269.  * External bindings that operate on the ORIGINAL images
  1270.  *****************************************************************{**/
  1271.  
  1272. typedef struct
  1273. {
  1274.     char *label;        /* button label               */
  1275.     char *shcmd;        /* shell command              */
  1276.     int multiargs;        /* true if accepts multi args */
  1277.     int confirm;        /* if confirm before doing it */
  1278. }
  1279. ib_ext_bind;
  1280.  
  1281. static ib_ext_bind ibext[MAXDIR], *ibb;
  1282.  
  1283. static void
  1284. copy_ibbind(ib_ext_bind * to, ib_ext_bind * from)
  1285. {
  1286.     to->multiargs = from->multiargs;
  1287.     to->confirm = from->confirm;
  1288.     StrReDup(to->label, from->label ? from->label : "?");
  1289.     StrReDup(to->shcmd, from->shcmd ? from->shcmd : "");
  1290. }
  1291.  
  1292. static int
  1293. no_binding(ib_ext_bind * b)
  1294. {
  1295.     return (!b->shcmd || !*b->shcmd);
  1296. }
  1297.  
  1298.  
  1299.  
  1300. /****************************************************************
  1301.  * Read bindings from disk or copy last binding. This routine
  1302.  * is guranteed to be called only once for each br
  1303.  ****************************************************************/
  1304. static const char *ibbindfile = "IbrowserBind";
  1305.  
  1306. #define READFMT  "%[^_]_ %[^_]_ %d %d"
  1307.  
  1308. static void
  1309. load_ibext(int br)
  1310. {
  1311.     FILE *fp;
  1312.  
  1313.     ibb = ibext + br;
  1314.  
  1315.     if ((fp = get_BITfile_fp(ibbindfile, "r")))
  1316.       {
  1317.       char buf[256];
  1318.       int baddef;
  1319.  
  1320.       buf[0] = '\0';    /* in case readline fails */
  1321.       baddef = readline(fp, buf, sizeof(buf)) == EOF;
  1322.       StrReDup(ibb->label, buf);
  1323.       baddef = baddef || readline(fp, buf, sizeof(buf)) == EOF;
  1324.       StrReDup(ibb->shcmd, buf);
  1325.       baddef = baddef || (ibb->confirm = readpint(fp)) < 0;
  1326.       baddef = baddef || (ibb->multiargs = readpint(fp)) < 0;
  1327.       fclose(fp);
  1328.  
  1329.       if (!baddef)
  1330.           return;
  1331.       }
  1332.  
  1333.     /* we got here only if bad defination or no defination at all */
  1334.  
  1335.     if (br == 0)
  1336.       {
  1337.       StrReDup(ibb->label, "?");
  1338.       }
  1339.     else
  1340.       {
  1341.       /* copy last binding */
  1342.       copy_ibbind(ibb, ibb - 1);
  1343.       }
  1344. }
  1345.  
  1346. /****** Write Current binding to Disk ****/
  1347.  
  1348. /* ARGSUSED */
  1349. static void
  1350. save_ibext(FL_OBJECT * ob, long br)
  1351. {
  1352.     FILE *fp;
  1353.  
  1354.     if (no_binding(ibb) || !(fp = get_BITfile_fp(ibbindfile, "w")))
  1355.     return;
  1356.  
  1357.     fprintf(fp, "%s\n%s\n %d %d %s\n", ibb->label, ibb->shcmd,
  1358.         ibb->confirm, ibb->multiargs, "confirm multiarg");
  1359.  
  1360.     fclose(fp);
  1361. }
  1362.  
  1363. /** Gather marked files into a single string ***/
  1364. static char *
  1365. gather_marked_files(int br)
  1366. {
  1367.     Thumb_t *p = ithumb[br];
  1368.     char *ha = 0, *oldha = "";
  1369.  
  1370.     while (p)
  1371.       {
  1372.       if (p->selected)
  1373.         {
  1374.         ha = vstrcat(oldha, " ", p->name, (char *) 0);
  1375.         if (*oldha)    /* not first time */
  1376.             free_vstrcat(oldha);
  1377.         oldha = ha;
  1378.         }
  1379.       p = p->next;
  1380.       }
  1381.     return ha;
  1382. }
  1383.  
  1384. static void
  1385. free_gathered_file(char *f)
  1386. {
  1387.     free_vstrcat(f);
  1388. }
  1389.  
  1390. /************************************************************************
  1391.  * Actually execute the binding with "?" repalced by filename(s)
  1392.  ************************************************************************/
  1393.  
  1394. static int
  1395. execute_it(int br, const char *cmd)
  1396. {
  1397.     int status;
  1398.  
  1399.     /*
  1400.      * protect "current directory", also it is very important to run the
  1401.      * shell command in correct directory
  1402.      */
  1403.     push_dir();
  1404.     status = (chdir(lastdir[br]) || system(cmd));
  1405.     pop_dir();
  1406.  
  1407.     return status;
  1408. }
  1409.  
  1410. static int
  1411. exe_multi_arg(int br)
  1412. {
  1413.     char *p, *all, *syscmd;
  1414.     char shcmd[1024];
  1415.     int ok;
  1416.  
  1417.     if (!(all = gather_marked_files(br)))
  1418.       {
  1419.       Bark("ExecuteIbBind", "No marked files");
  1420.  
  1421.       /* return 0 to shut up message generator */
  1422.       return 0;
  1423.       }
  1424.  
  1425.     Strncpy(shcmd, ibb->shcmd, sizeof(shcmd) - 1);
  1426.  
  1427.     /*
  1428.      * generate complete shell command on the fly, replacing '?' with
  1429.      * applicable file names
  1430.      */
  1431.  
  1432.     if ((p = strchr(shcmd, '?')))
  1433.     *p++ = '\0';
  1434.  
  1435.     syscmd = vstrcat(shcmd, " ", all, p, (char *) 0);
  1436.  
  1437.     /* no use for the marked file list, free it */
  1438.     free_gathered_file(all);
  1439.  
  1440.     M_info("ExecuteIbBind", "CMD=%s", syscmd);
  1441.  
  1442.     ok = execute_it(br, syscmd) == 0;
  1443.  
  1444.     free_vstrcat(syscmd);
  1445.     return !ok;
  1446. }
  1447.  
  1448. /**********************************************************************
  1449.  * Run a loop over all marked files. Abort on first failure
  1450.  **********************************************************************/
  1451. static int
  1452. exe_single_arg(int br)
  1453. {
  1454.     Thumb_t *t = ithumb[br];
  1455.     char shcmd[1024], *p, *syscmd;
  1456.     int ok = 1;
  1457.  
  1458.  
  1459.     /* breaking up the command */
  1460.     Strncpy(shcmd, ibb->shcmd, sizeof(shcmd) - 1);
  1461.  
  1462.     if ((p = strchr(shcmd, '?')))
  1463.     *p++ = '\0';
  1464.  
  1465.     while (t && ok)
  1466.       {
  1467.       if (t->selected)
  1468.         {
  1469.         syscmd = vstrcat(shcmd, " ", t->name, p, (char *) 0);
  1470.         ok = execute_it(br, syscmd) == 0;
  1471.         free_vstrcat(syscmd);
  1472.         }
  1473.       t = t->next;
  1474.       }
  1475.  
  1476.     return !ok;
  1477.  
  1478. }
  1479.  
  1480. static void
  1481. execute_ibext(int br)
  1482. {
  1483.     ibb = ibext + br;
  1484.  
  1485.     if (ibb->confirm && !yes_no("ExecuteBinding", ibb->shcmd, "", 0))
  1486.     return;
  1487.  
  1488.     if ((ibb->multiargs ? exe_multi_arg : exe_single_arg) (br))
  1489.     Bark("ExecuteBinding", "Something is wrong");
  1490.  
  1491. }
  1492.  
  1493. static void get_ibext(int);
  1494.  
  1495. static void
  1496. ext_bind_cb(FL_OBJECT * ob, long br)
  1497. {
  1498.     ibb = ibext + br;
  1499.  
  1500.     switch (fl_get_button_numb(ob))
  1501.       {
  1502.       case 1:            /* right mouse */
  1503.       get_ibext(br);
  1504.       break;
  1505.       case 2:            /* middle mouse */
  1506.       case 3:            /* left mouse */
  1507.       /* if no binding is defined, define it now */
  1508.       (no_binding(ibb) ? get_ibext : execute_ibext) (br);
  1509.       break;
  1510.       }
  1511. }
  1512.  
  1513. static FL_FORM *ibbind;
  1514. static FL_OBJECT *ibbut[MAXDIR];
  1515. static void create_form_ibbind(void);
  1516.  
  1517. static void
  1518. show_ibbut(int br)
  1519. {
  1520.     ibb = ibext + br;
  1521.  
  1522.     if (!ibb->shcmd || !*ibb->shcmd)
  1523.     return;
  1524.     fl_set_object_label(ibbut[br], ibb->label ? ibb->label : ibb->shcmd);
  1525. }
  1526.  
  1527. static void
  1528. get_ibext(int br)
  1529. {
  1530.     short val;
  1531.  
  1532.     ibb = ibext + br;
  1533.  
  1534.     create_form_ibbind();
  1535.  
  1536.     fl_deactivate_all_forms();
  1537.  
  1538.     bit_show_form(ibbind, FL_PLACE_CENTER, 0, "");
  1539.     while (bit_qread(&val) != F1KEY || !val)
  1540.     ;
  1541.     bit_hide_form(ibbind);
  1542.     show_ibbut(br);
  1543.  
  1544.     fl_activate_all_forms();
  1545. }
  1546.  
  1547. /* ARGSUSED */
  1548. static void
  1549. get_cmd_cb(FL_OBJECT * ob, long q)
  1550. {
  1551.     const char *p = fl_get_input(ob);
  1552.  
  1553.     if (p && *p)
  1554.       {
  1555.       StrReDup(ibb->shcmd, p);
  1556.       }
  1557.     else
  1558.       {
  1559.       free(ibb->shcmd);
  1560.       ibb->shcmd = 0;
  1561.       }
  1562. }
  1563.  
  1564. /* ARGSUSED */
  1565. static void
  1566. get_lab_cb(FL_OBJECT * ob, long q)
  1567. {
  1568.     const char *p = fl_get_input(ob);
  1569.     StrReDup(ibb->label, (p && *p) ? p : "?");
  1570. }
  1571.  
  1572. static void
  1573. get_ibopt_cb(FL_OBJECT * ob, long q)
  1574. {
  1575.     if (q == 0)
  1576.     ibb->confirm = fl_get_button(ob);
  1577.     else
  1578.     ibb->multiargs = fl_get_button(ob);
  1579. }
  1580.  
  1581. /* ARGSUSED */
  1582. static void
  1583. ibbind_done(FL_OBJECT * ob, long q)
  1584. {
  1585.     fl_qenter(F1KEY, 1);
  1586. }
  1587.  
  1588. static void
  1589. create_form_ibbind(void)
  1590. {
  1591.     FL_OBJECT *obj;
  1592.  
  1593.     if (ibbind)
  1594.     return;
  1595.  
  1596.     ibbind = fl_bgn_form(FL_NO_BOX, 270.0, 180.0);
  1597.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 270.0, 180.0, "");
  1598.     fl_set_object_color(obj, 12, 47);
  1599.     obj = fl_add_box(FL_DOWN_BOX, 10.0, 10.0, 250.0, 160.0, "");
  1600.     fl_set_object_color(obj, 12, 47);
  1601.     obj = fl_add_button(FL_HB, 0.0, 0.0, 270.0, 180.0, "");
  1602.     fl_set_call_back(obj, help_cb, HELP_IBBIND);
  1603.  
  1604.     obj = fl_add_input(FL_NORMAL_INPUT, 90.0, 120.0, 160.0, 30.0, "Label");
  1605.     fl_set_object_color(obj, 47, 52);
  1606.     fl_set_object_lsize(obj, 10.000000);
  1607.     fl_set_input_return(obj, 1);
  1608.     fl_set_call_back(obj, get_lab_cb, 0);
  1609.  
  1610.     obj = fl_add_input(FL_NORMAL_INPUT, 90.0, 90.0, 160.0, 30.0, "Command");
  1611.     fl_set_object_color(obj, 47, 52);
  1612.     fl_set_object_lsize(obj, 10.000000);
  1613.     fl_set_input_return(obj, 1);
  1614.     fl_set_call_back(obj, get_cmd_cb, 0);
  1615.  
  1616.     obj = fl_add_roundbutton(FL_PB, 20.0, 50.0, 30.0, 30.0, "Confirm");
  1617.     fl_set_object_color(obj, 47, 3);
  1618.     fl_set_object_lsize(obj, 10.000000);
  1619.     fl_set_call_back(obj, get_ibopt_cb, 0);
  1620.     obj = fl_add_roundbutton(FL_PB, 110.0, 50.0, 30.0, 30.0, "MultiArgs");
  1621.     fl_set_object_color(obj, 47, 3);
  1622.     fl_set_object_lsize(obj, 10.000000);
  1623.     fl_set_call_back(obj, get_ibopt_cb, 1);
  1624.  
  1625.     obj = fl_add_button(FL_NB, 50.0, 20.0, 55.0, 25.0, "Save");
  1626.     fl_set_call_back(obj, save_ibext, 0);
  1627.  
  1628.     obj = fl_add_button(FL_NB, 190.0, 20.0, 55.0, 25.0, "OK");
  1629.     fl_set_object_lsize(obj, 10.000000);
  1630.     fl_set_call_back(obj, ibbind_done, 0);
  1631.     fl_end_form();
  1632. }
  1633.  
  1634.  
  1635. /****** End of ext binding ***********}***/
  1636.  
  1637. /*******************************************************************
  1638.  * All control functions
  1639.  ******************************************************************/
  1640. typedef struct
  1641. {
  1642.     const char *l;
  1643.     void (*cb) (FL_OBJECT *, long);
  1644.     const char *scut;
  1645.     int c;
  1646. }
  1647. Cb_t;
  1648.  
  1649. static Cb_t cbs[] =
  1650. {
  1651.     {"MarkAll", mark_all, 0, FL_YELLOW},
  1652.     {"UnMarkAll", unmark_all, 0, FL_GREEN},
  1653.     {"Add2List", add_cb, 0, FL_GREEN},
  1654.     {"Delete", del_cb, 0, FL_YELLOW},
  1655.     {"DelAll", delall_cb, 0, FL_RED}
  1656. };
  1657.  
  1658.  
  1659. /***********************************************************************
  1660.  * Hack to make redraw in single buffer a little nicer
  1661.  ***********************************************************************/
  1662.  
  1663. #ifndef S100x80
  1664.  
  1665. static void
  1666. create_browser_80x60(int br)
  1667. {
  1668.     FL_OBJECT *obj;
  1669.     float dx, dy, x, y;
  1670.     int i, j, k;
  1671.     float formw = 505.0, formh = 370.0;
  1672.  
  1673.     if (ibrowser[br])
  1674.     return;
  1675.  
  1676.     load_ibext(br);
  1677.  
  1678.     ibrowser[br] = fl_bgn_form(FL_UP_BOX, formw, formh);
  1679.     obj = fl_add_button(FL_HB, 0, 0, formw, formh, "");
  1680.     fl_set_call_back(obj, help_cb, HELP_IBR);
  1681.  
  1682.     dnbox[br] = obj = fl_add_box(FL_DOWN_BOX, 10.0, 40.0, 470.0, 295.0, "");
  1683.  
  1684.  
  1685.     pager[br] = fl_bgn_group();
  1686.  
  1687.     /* paging */
  1688.     dx = 20;
  1689.     x = formw - dx - 5.;
  1690.     y = 43.0;
  1691.  
  1692.     /* down button */
  1693.     dnb[br] = obj = fl_add_button(FL_NB, x, y, dx, dx, "@2");
  1694.     fl_set_call_back(obj, next_cb, br);
  1695.     fl_set_object_lcol(obj, FL_RED);
  1696.  
  1697.     /* slider */
  1698.     y += dx;
  1699.  
  1700.     dy = 295 - 2 * dx - 3;
  1701.  
  1702.     sld[br] = obj = fl_add_slider(FL_VERT_NICE_SLIDER, x, y, dx, dy, "");
  1703.     fl_set_object_boxtype(obj, FL_BORDER_BOX);
  1704.     fl_set_object_color(obj, FL_MAGIC1, FL_RED);
  1705.     fl_set_slider_return(obj, 0);
  1706.     fl_set_call_back(obj, slider_cb, br);
  1707.     fl_set_slider_value(obj, 1.0);
  1708.  
  1709.     /* up button */
  1710.     y += dy;
  1711.     upb[br] = obj = fl_add_button(FL_NB, x, y + 1, dx, dx, "@8");
  1712.     fl_set_call_back(obj, prev_cb, br);
  1713.     fl_set_object_lcol(obj, FL_RED);
  1714.  
  1715.     fl_end_group();
  1716.  
  1717.  
  1718.     y = 340;
  1719.     x = 10.0;
  1720.     dy = 23;
  1721.  
  1722.     dx = 70;
  1723.     nfiles[br] = obj = fl_add_text(FL_NT, x, y, dx, dy, "");
  1724.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1725.     fl_set_object_lsize(obj, 8.0);
  1726.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1727.  
  1728.     x += dx;
  1729.     dx = 40;
  1730.     obj = fl_add_button(FL_NB, x, y, dx, dy, "../");
  1731.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1732.     fl_set_object_lsize(obj, 11.0);
  1733.     fl_set_call_back(obj, parent_cb, br);
  1734.  
  1735.     /* current directory: may display about 40 charactors */
  1736.     x += dx;
  1737.     dx = 170;
  1738.     title[br] = obj = fl_add_text(FL_NT, x, y, dx, dy, "");
  1739.     fl_set_object_lsize(obj, 10.0);
  1740.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1741.  
  1742.     x += dx;
  1743.     dx = 65;
  1744.     obj = fl_add_button(FL_NB, x, y, dx, dy, "NewDir");
  1745.     fl_set_object_lsize(obj, 10.0);
  1746.     fl_set_call_back(obj, newdir_cb, br);
  1747.  
  1748.     x += dx;
  1749.     obj = fl_add_button(FL_NB, x, y, dx, dy, "Update");
  1750.     fl_set_object_lsize(obj, 10.0);
  1751.     fl_set_call_back(obj, update_cb, br);
  1752.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  1753.  
  1754.     x += dx;
  1755.     obj = fl_add_button(FL_NB, x, y, dx, dy, "ReScan");
  1756.     fl_set_object_lsize(obj, 10.0);
  1757.     fl_set_call_back(obj, rescan_cb, br);
  1758.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  1759.  
  1760.     x = 18;
  1761.     y = 265;
  1762.     dx = 91;
  1763.     dy = 92;
  1764.     for (i = k = 0; i < 3; i++, x = 20, y -= dy)
  1765.     for (j = 0; j < 5; j++, x += dx)
  1766.       {
  1767.           icons[br][k++] = obj =
  1768.           fl_add_icon(FL_DBL_CLK_ICON, x, y, 80.0, 60.0, "");
  1769.           fl_set_object_boxtype(obj, FL_NO_BOX);
  1770.           fl_set_object_lsize(obj, 8.0);
  1771.           fl_set_object_lstyle(obj, FL_NORMAL_STYLE);
  1772.           fl_set_object_align(obj, FL_ALIGN_BOTTOM);
  1773.           fl_set_call_back(obj, handle_it, br);
  1774.       }
  1775.  
  1776.     dx = 65;
  1777.     dy = 25;
  1778.     x = 10.0;
  1779.     y = 10.0;
  1780.     for (i = 0; i < sizeof(cbs) / sizeof(cbs[0]); i++, x += dx)
  1781.       {
  1782.       obj = fl_add_button(FL_NB, x, y, dx, dy, cbs[i].l);
  1783.       fl_set_object_lsize(obj, 10.0);
  1784.       fl_set_object_color(obj, FL_MAGIC1, cbs[i].c);
  1785.       fl_set_call_back(obj, cbs[i].cb, br);
  1786.       }
  1787.  
  1788.     /* external bindings */
  1789.     ibbut[br] = obj = fl_add_button(FL_NB, x, y, dx, dy, ibext[br].label);
  1790.     fl_set_object_lsize(obj, 10.0);
  1791.     fl_set_call_back(obj, ext_bind_cb, br);
  1792.     x += dx;
  1793.  
  1794.     obj = fl_add_button(FL_NB, 490 - dx - 8, y, dx, dy, "Close");
  1795.     fl_set_object_lsize(obj, 10.0);
  1796.     fl_set_call_back(obj, finish_it, br);
  1797.  
  1798.     fl_end_form();
  1799. }
  1800.  
  1801. #else
  1802.  
  1803. static void
  1804. create_browser_100x80(int br)
  1805. {
  1806.     FL_OBJECT *obj;
  1807.     float x, y, dx, dy;
  1808.     int i, j, k;
  1809.     float formw = 620, formh = 440;
  1810.  
  1811.  
  1812.     if (ibrowser[br])
  1813.     return;
  1814.  
  1815.     load_ibext(br);
  1816.  
  1817.     ibrowser[br] = fl_bgn_form(FL_UP_BOX, formw, formh);
  1818.     obj = fl_add_button(FL_HB, 0, 0, formw, formh, "");
  1819.     fl_set_call_back(obj, help_cb, HELP_IBR);
  1820.  
  1821.     dnbox[br] = obj = fl_add_box(FL_DOWN_BOX, 10.0, 40.0, 580.0, 360.0, "");
  1822.  
  1823.     /* pager group */
  1824.     pager[br] = fl_bgn_group();
  1825.  
  1826.     dx = 20;
  1827.     x = formw - 7 - dx;
  1828.     y = 43;
  1829.  
  1830.     dnb[br] = obj = fl_add_button(FL_NB, x, y, dx, dx, "@2");
  1831.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1832.     fl_set_object_lcol(obj, 1);
  1833.     fl_set_call_back(obj, next_cb, br);
  1834.  
  1835.     y += dx + 1;
  1836.     dy = 360 - 2 * dx - 3;
  1837.  
  1838.     sld[br] = obj = fl_add_slider(FL_VERT_NICE_SLIDER, x, y, dx, dy, "");
  1839.     fl_set_object_boxtype(obj, FL_BORDER_BOX);
  1840.     fl_set_object_color(obj, FL_MAGIC1, FL_RED);
  1841.     fl_set_slider_return(obj, 0);
  1842.     fl_set_call_back(obj, slider_cb, br);
  1843.     fl_set_slider_value(obj, 1.0);
  1844.  
  1845.     y += dy;
  1846.  
  1847.     upb[br] = obj = fl_add_button(FL_NB, x, y, dx, dx, "@8");
  1848.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1849.     fl_set_object_lcol(obj, 1);
  1850.     fl_set_call_back(obj, prev_cb, br);
  1851.  
  1852.     fl_end_group();
  1853.  
  1854.     dy = 23;
  1855.     y = 405;
  1856.     dx = 100.0;
  1857.  
  1858.     nfiles[br] = obj = fl_add_text(FL_NT, 10.0, y, dx, dy, "");
  1859.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1860.     fl_set_object_lsize(obj, 8.0);
  1861.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1862.  
  1863.     obj = fl_add_button(FL_NB, 120, y, 30, dy, "../");
  1864.     fl_set_object_lsize(obj, 11.0);
  1865.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1866.     fl_set_call_back(obj, parent_cb, br);
  1867.  
  1868.     title[br] = obj = fl_add_text(FL_NT, 190.0, y, 190.0, dy, "");
  1869.     fl_set_object_lsize(obj, 10.0);
  1870.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1871.  
  1872.     obj = fl_add_button(FL_NB, 400, y, 80, dy, "NewDir");
  1873.     fl_set_object_lsize(obj, 10.0);
  1874.     fl_set_call_back(obj, newdir_cb, br);
  1875.  
  1876.     obj = fl_add_button(FL_NB, 480, y, 80, dy, "Update");
  1877.     fl_set_object_lsize(obj, 10.0);
  1878.     fl_set_call_back(obj, update_cb, br);
  1879.  
  1880.     x = 20.0;
  1881.     y = 310;
  1882.     dx = 113.0;
  1883.     dy = 113;
  1884.  
  1885.     for (i = k = 0; i < 3; i++, x = 20.0, y -= dy)
  1886.     for (j = 0; j < 5; j++, x += dx)
  1887.       {
  1888.           icons[br][k++] = obj = fl_add_icon(FL_DBL_CLK_ICON,
  1889.                          x, y, 100.0, 80.0, "");
  1890.           fl_set_object_boxtype(obj, FL_NO_BOX);
  1891.           fl_set_object_lsize(obj, 8.0);
  1892.           fl_set_object_lstyle(obj, FL_NORMAL_STYLE);
  1893.           fl_set_object_align(obj, FL_ALIGN_BOTTOM);
  1894.           fl_set_call_back(obj, handle_it, br);
  1895.       }
  1896.  
  1897.  
  1898.     dx = 70;
  1899.     dy = 25;
  1900.     x = y = 10.0;
  1901.     for (i = 0; i < sizeof(cbs) / sizeof(cbs[0]); i++, x += dx)
  1902.       {
  1903.       obj = fl_add_button(FL_NB, x, y, dx, dy, cbs[i].l);
  1904.       fl_set_object_lsize(obj, 10.0);
  1905.       fl_set_object_color(obj, FL_MAGIC1, cbs[i].c);
  1906.       fl_set_call_back(obj, cbs[i].cb, br);
  1907.       }
  1908.  
  1909.  
  1910.  
  1911.     obj = fl_add_button(FL_NB, 520.0, 10.0, dx, dy, "Close");
  1912.     fl_set_object_lsize(obj, 10.0);
  1913.     fl_set_call_back(obj, finish_it, br);
  1914.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1915.  
  1916.  
  1917.     fl_end_form();
  1918. }
  1919.  
  1920. #endif
  1921.